﻿#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

#include <opencv2/features2d.hpp>

#include <vector>
#include <iostream>

using namespace std;
using namespace cv;

static int demoFitLine()
{
       //创建一个用于绘制图像的空白图
    cv::Mat image = cv::Mat::zeros(480, 640, CV_8UC3);

    //输入拟合点
    std::vector<cv::Point> points;
    points.push_back(cv::Point(48, 58));
    points.push_back(cv::Point(105, 98));
    points.push_back(cv::Point(155, 160));
    points.push_back(cv::Point(212, 220));
    points.push_back(cv::Point(248, 260));
    points.push_back(cv::Point(320, 300));
    points.push_back(cv::Point(350, 360));
    points.push_back(cv::Point(412, 400));
 
    //将拟合点绘制到空白图上
    for (int i = 0; i < points.size(); i++)
    {
        cv::circle(image, points[i], 5, cv::Scalar(0, 0, 255), 2, 8, 0);
    }
 
    cv::Vec4f line_para; 
    cv::fitLine(points, line_para, cv::DIST_L2, 0, 1e-2, 1e-2);
 
    std::cout << "line_para = " << line_para << std::endl;
 
    //获取点斜式的点和斜率
    cv::Point point0;
    point0.x = line_para[2];
    point0.y = line_para[3];
 
    double k = line_para[1] / line_para[0];
 
    //计算直线的端点(y = k(x - x0) + y0)
    cv::Point point1, point2;
    
    // point1.x = 0;
    // point1.y = k * (0 - point0.x) + point0.y;
    // point2.x = 640;
    // point2.y = k * (640 - point0.x) + point0.y;

    // 计算误差
    double a = line_para[1];
    double b = -line_para[0];
    double c = line_para[0] * line_para[3] - line_para[1] * line_para[2];
    point1.x = 0;
    point1.y = -(a*point1.x + c)/b;
    point2.x = 640;
    point2.y = -(a*point2.x + c)/b;
 
    cv::line(image, point1, point2, cv::Scalar(0, 255, 0), 2, 8, 0);
 

    for (size_t i = 0; i < points.size(); i++)
    {
        double err = fabs(a* points[i].x + b* points[i].y + c);
        cout << i << " : " << err << endl;
    }
    

    cv::imshow("image", image);
    cv::waitKey(0);

    return 0;
}

static void demoBlobDector()
{
    string filename = "D:/tmp/balls/small.bmp";
    string outputfolder = "D:/tmp/balls/out/";

        std::vector<KeyPoint> keyPoints;
    Mat image = imread(filename, IMREAD_GRAYSCALE);

    // BlobDector
    SimpleBlobDetector::Params blobParams;
    blobParams.thresholdStep = 10; // 二值化的阈值步长
    blobParams.minThreshold = 60; // 二值化的起始阈值，即公式1的T1
    blobParams.maxThreshold = 110; // 二值化的终止阈值，即公式1的T2
    blobParams.minDistBetweenBlobs = 10;

    blobParams.filterByCircularity = false; // 斑点圆度的限制变量，默认是不限制

    blobParams.filterByConvexity = true; // 斑点凸度的限制变量
    blobParams.minConvexity = 0.9f; // 斑点的最小凸度
    blobParams.maxConvexity = std::numeric_limits<float>::max(); // 斑点的最大凸度

    blobParams.filterByColor = true; // 斑点颜色的限制变量
    blobParams.blobColor = 255; // 0表示只提取黑色斑点；如果该变量为255，表示只提取白色斑点
    blobParams.minArea = 100; // 斑点的最小面积
    blobParams.maxArea = 900; // 斑点的最大面积

    cout << "maxConvexity:" << blobParams.maxConvexity << endl;
    Ptr<SimpleBlobDetector> blobDetector = SimpleBlobDetector::create(blobParams);
    blobDetector->detect(image, keyPoints);

    cout << keyPoints.size() << endl;
    // drawKeypoints(image, keyPoints, image, Scalar(255,0,0));
    Scalar color = Scalar(255, 0, 0);
    for (size_t i = 0; i < keyPoints.size(); i++)
    {
        circle(image, keyPoints[i].pt, keyPoints[i].size/2.0, color, 0);
    }
    

    // imwrite(outputfolder + "result.bmp", image);
    //Mat outImage;
    //resize(image, outImage, Size(), 0.5, 0.5, INTER_LINEAR  );
    namedWindow("blobs", 0);
    imshow("blobs", image);

    waitKey();
}

int main(int argc, char const *argv[])
{
    int option =2;
    switch (option)
    {
    case 1:
        demoFitLine();
        break;
    case 2:
        demoBlobDector();
        break;

    default:
        break;
    }
}
